#include "util.h"
#include "log.h"
#include "fiber.h"
#include <execinfo.h>
#include <sys/time.h>

namespace framework
{
    framework::Logger::ptr g_logger = FRAMEWORK_LOG_NAME("system");

    //获取当前线程id
    pid_t GetThreadId()
    {
        return syscall(SYS_gettid);
    }

    //获取协程id
    uint32_t GetFiberId()
    {
        return framework::Fiber::GetFiberId();
    }

    //获取当前的调用栈
    //bt 保存调用栈 //size 最多返回层数 //skip 跳过栈顶的层数
    void Backtrace(std::vector<std::string>& bt, int size, int skip)
    {
        void** array = (void**)malloc((sizeof(void*) * size));

        //backtrace用于在程序崩溃时获取程序堆栈信息
        //buffer：指向指针数组的指针，用于存储堆栈跟踪信息。
        //size：指定存储堆栈跟踪信息的最大帧数。
        //函数会将调用堆栈的返回地址依次存储到buffer指向的数组中，直到达到指定的最大帧数或者堆栈信息已经全部存储完毕。
        //函数返回实际存储的帧数 失败返回负数
        //因为backtrace()函数通常不是在当前代码文件中定义的，而是在操作系统提供的动态库中实现的，所以需要使用作用域运算符来明确指定函数的全局作用域。在这种情况下，使用::backtrace()可以确保调用的是全局作用域中的backtrace()函数。
        size_t s = ::backtrace(array, size);
        

        //backtrace_symbols用于将backtrace()函数获取到的堆栈跟踪信息转换为可读字符串
        //buffer：指向指针数组的指针，这个指针数组包含由backtrace()获取的堆栈跟踪信息。
        //size：指定buffer数组中包含的帧数。
        //函数返回一个字符串数组，每个字符串表示一个函数调用的堆栈信息  失败返回NULL
        char** strings = backtrace_symbols(array, s);
        if(NULL == strings)
        {
            FRAMEWORK_LOG_ERROR(g_logger) << "backtrace_synbols error";
            free(array);
            return;
        }

        for(size_t i = skip; i < s; ++i)
        {
            //bt.push_back(demangle(strings[i]));
            bt.push_back(strings[i]);
        }

        free(strings);
        free(array);
    }

    //获取当前栈信息的字符串
    //size 栈的最大层数 //skip 跳过栈顶的层数 //prefix 栈信息前输出的内容
    std::string BacktraceToString(int size, int skep, const std::string& prefix)
    {   
        std::vector<std::string> bt;
        Backtrace(bt, size, skep);
        std::stringstream ss;
        ss << std::endl;
        for(size_t i = 0; i < bt.size(); ++i)
        {
            ss << prefix << bt.at(i) << std::endl;
        }
        return ss.str();
    }

    //获取当前时间的毫秒
    uint64_t GetCurrentMS()
    {
        struct timeval tv;
        //第二个参数为时区，NULL为默认时区
        gettimeofday(&tv, NULL);
        return tv.tv_sec * 1000ul + tv.tv_usec /1000; //秒*1000，纳秒/1000
    }

    //获取当前时间的微秒
    uint64_t GetCurrentUS()
    {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        return tv.tv_usec * 1000 * 1000ul + tv.tv_usec;
    }

}
